from machine import I2S, Pin
import time
import gc


class Inmp441:
    def __init__(self, sck_pin, ws_pin, sd_pin, i2s_num=0, sample_rate=8000):
        self.__sck = sck_pin
        self.__ws = ws_pin
        self.__sd = sd_pin
        self.__i2s = i2s_num
        self.__sample_rate = sample_rate
        self.__instance = None
        self.output_file = f"/output_{sample_rate}hz.pcm"
        self.is_listening = False
        self.__file_handle = None

        self.__ibuf_size = 32000
        self.__buffer_size = 16 * 1000

        self.init()

    def init(self):
        if self.__instance:
            return

        try:
            self.__instance = I2S(
                self.__i2s,
                sck=Pin(self.__sck),
                ws=Pin(self.__ws),
                sd=Pin(self.__sd),
                mode=I2S.RX,
                bits=16,
                format=I2S.MONO,
                rate=self.__sample_rate,
                ibuf=self.__ibuf_size,
            )
            print(f"INMP441初始化成功: {self.__sample_rate}Hz")
        except Exception as e:
            print(f"INMP441初始化失败: {e}")
            self.__instance = None

    def record_bytes(self, target_bytes):
        if not self.__instance:
            print("I2S实例未初始化，尝试重新初始化...")
            return None

        self.is_listening = True

        buffer = bytearray(target_bytes)
        buffer_view = memoryview(buffer)

        try:
            num_bytes = self.__instance.readinto(buffer_view)
        except Exception as e:
            print("录音错误:", e)
            return None

        if num_bytes is None or num_bytes == 0:
            return None

        return buffer[:num_bytes]

    def listen(self, duration_sec=10):
        if not self.__instance:
            return
        common.collect_gc()
        self.is_listening = True
        self.clear()
        self.__file_handle = open(self.output_file, "wb")

        buf = bytearray(self.__buffer_size)
        view = memoryview(buf)
        common.print_gc_info()

        target_bytes = self.__sample_rate * 2 * duration_sec
        total_bytes = 0

        start_time = time.time()

        try:
            while self.is_listening and total_bytes < target_bytes:
                num = self.__instance.readinto(view)

                if num > 0:
                    to_write = min(num, target_bytes - total_bytes)
                    self.__file_handle.write(view[:to_write])
                    total_bytes += to_write

                if total_bytes % (self.__sample_rate * 2) == 0:
                    actual_sec = total_bytes / (self.__sample_rate * 2)
                    elapsed_sec = time.time() - start_time
                    print(
                        f"[DEBUG] 已录制: {actual_sec:.2f}s (物理运行时间: {elapsed_sec:.2f}s)"
                    )

        except Exception as e:
            print("录音错误:", e)

        finally:
            if self.__file_handle:
                self.__file_handle.close()
                self.__file_handle = None

            self.is_listening = False
            actual_duration = total_bytes / (self.__sample_rate * 2)
            print(
                f"录音完成: {self.output_file}, {total_bytes} bytes, {actual_duration:.2f}s"
            )

    def stop(self):
        self.is_listening = False
        if self.__file_handle:
            self.__file_handle.close()
            self.__file_handle = None
        if self.__instance:
            self.__instance.deinit()
            self.__instance = None

    def stop_listening(self):
        self.is_listening = False
        if self.__file_handle:
            self.__file_handle.close()
            self.__file_handle = None

    def clear(self):
        try:
            import os

            os.remove(self.output_file)
        except Exception as e:
            print("清空文件失败:", e)


if __name__ == "__main__":
    from utils import common

    common.collect_gc()
    common.print_gc_info()

    print("=== INMP441 性能测试 ===")

    sample_rates = [8000, 16000]
    test_duration = 6

    for rate in sample_rates:
        print(f"\n测试{rate}Hz采样率:")
        mic = Inmp441(2, 1, 0, sample_rate=rate)
        mic.listen(duration_sec=test_duration)
        gc.collect()
